package com.qzw.study.circledepend;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author quziwei
 * @date 2020/10/06
 * @description
 **/
public class MainStart {
	//一级缓存
	private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
	//二级缓存
	private static Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
	//三级缓存
	private static Map<String, ObjectFactory> singletonFactories = new ConcurrentHashMap<>();
	//循环依赖标识
	private static Set<String> singletonCurrentlyCreation = new HashSet<>();
	/**
	 * 二级缓存：为了将我们成熟的Bean和我们的纯洁Bean分离开来。避免读取到不完整的Bean
	 */
	private static Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>();

	public static void main(String[] args) throws Exception {
		//加载配置类
		loadBeanDefinition();
		//注册BeanPostProcessor

		//循环创建Bean
		beanDefinitionMap.forEach((k, v) -> {
			try {
				getBean(k);
			} catch (Exception e) {
				e.printStackTrace();
			}
		});
		A a = (A) getBean("a");

	}

	//获取Bean
	public static Object getBean(String beanName) throws Exception {

		Object sigleton = getSigleton(beanName);
		if (sigleton != null) {
			return sigleton;
		}
		//标记正在创建
		if (!singletonCurrentlyCreation.contains(beanName)) {
			singletonCurrentlyCreation.add(beanName);
		}
		//createBean

		//实例化
		RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
		Class<?> beanClass = beanDefinition.getBeanClass();
		Object instance = beanClass.newInstance();
		//创建动态代理(BeanPostProcessor)
		singletonFactories.put(beanName, () -> {
			return new JdkProxyBeanPostProcessor().getEarlyBeanReference(earlySingletonObjects.get(beanName), beanName);
		});
//		//添加到二级缓存
//		earlySingletonObjects.put(beanName, instance);
		//属性赋值
		Field[] declaredFields = instance.getClass().getDeclaredFields();
		for (Field declaredField : declaredFields) {
			Autowired annotation = declaredField.getAnnotation(Autowired.class);
			if (annotation != null) {
				declaredField.setAccessible(true);
				//byName byType byConstructor
				Object bean = getBean(declaredField.getName());
				declaredField.set(instance, bean);

			}
		}
		//初始化
		//放在这里创建AOP已经晚了。 B里面的A不是一个代理了

		//要先从二级缓存当中拿一下
		if (earlySingletonObjects.containsKey(beanName)) {
			instance = earlySingletonObjects.get(beanName);
		}
		//这时候我赋值进去的A就是一个动态代理的A
		//添加到一级缓存
		singletonObjects.put(beanName, instance);

		//remove 二级缓存和三级缓存
		return instance;
	}

	private static Object getSigleton(String beanName) {
		Object bean = singletonObjects.get(beanName);
		//如果一级缓存当中没有，并且还有在循环依赖标识当中存在，说明是循环依赖
		if (bean == null && singletonCurrentlyCreation.contains(beanName)) {
			//如果二级缓存当中有，就直接返回二级缓存当中的
			if (earlySingletonObjects.containsKey(beanName)) {
				return earlySingletonObjects.get(beanName);
			}
			//如果是循环依赖先去三级缓存当中创建动态代理,从三级缓存当中拿
			ObjectFactory objectFactory = singletonFactories.get(beanName);
			if (objectFactory != null) {
				Object factoryObject = objectFactory.getObject();
				earlySingletonObjects.put(beanName, factoryObject);
			}
		}
		return bean;
	}

	public static void loadBeanDefinition() {
		RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(A.class);
		RootBeanDefinition rootBeanDefinition1 = new RootBeanDefinition(B.class);
		beanDefinitionMap.put("a", rootBeanDefinition);
		beanDefinitionMap.put("b", rootBeanDefinition1);
	}
}
